#include "RCSpriteBatch.h"
#include "RCGame.h"
#include <algorithm>

RCSpriteBatch::RCSpriteBatch(IRCGraphicsDevice *graphicsDevice)
{
	bBegan = false;
	pGraphicsDevice = graphicsDevice;

	D3D11_INPUT_ELEMENT_DESC l[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,   0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,      0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },		
		{ "instanceTransform", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
        { "instanceTransform", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
        { "instanceTransform", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
        { "instanceTransform", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
		
    };


	memcpy(layout,l,sizeof(D3D11_INPUT_ELEMENT_DESC) * ARRAYSIZE(l));

	PositionTexVertex v[] =
    {
        { XMFLOAT3( -1.0f, 1.0f, 0.0f ), XMFLOAT2(  0.0f, 1.0f ) },
        { XMFLOAT3( -1.0f, -1.0f, 0.0f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, 0.0f ), XMFLOAT2(  1.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, 0.0f ), XMFLOAT2(   1.0f, 1.0f ) },  
    };

	memcpy(vertices,v,sizeof(PositionTexVertex) * ARRAYSIZE(v));

	WORD i[] =
    {
		0,1,2,
        2,3,0,
    };

	memcpy(indices,i,sizeof(WORD) * ARRAYSIZE(i));

	pVertexShader = nullptr;
}

RCSpriteBatch::RCSpriteBatch(void)
{
	bBegan = false;	
}


RCSpriteBatch::~RCSpriteBatch(void)
{
	bBegan = false;

	free(layout);
	free(vertices);
	free(indices);

	pVertexShader->Release();
	pVertexShaderInstanced->Release();
	pPixelShader->Release();

	pIndexBuffer->Release();
	pVertexBuffer->Release();

	pVertexLayout->Release();
	pParameters->Release();

	pBlendState->Release();
	pDepthStencilState->Release();
	pSamplerState->Release();
	pRasterizerState->Release();
	

	spriteList.clear();
}

XMMATRIX RCSpriteBatch::GetViewportTransform()
{
    // Look up the current viewport.
    D3D11_VIEWPORT viewport;
    UINT viewportCount = 1;

	viewport = pGraphicsDevice->getViewPort();

    if (viewportCount != 1)
	{
		MessageBox( NULL, L"No viewport is set", L"Warning", MB_OK );
        throw std::exception("No viewport is set");
	}

    // Compute the matrix.
    float xScale = (viewport.Width  > 0) ? 2.0f / viewport.Width  : 0.0f;
    float yScale = (viewport.Height > 0) ? 2.0f / viewport.Height : 0.0f;

    return XMMATRIX
    (
         xScale,  0,       0,  0,
         0,      -yScale,  0,  0,
         0,       0,       1,  0,
        -1,       1,       0,  1
    );
}

void RCSpriteBatch::Begin(SpriteSortMode sortMode, _In_opt_ ID3D11BlendState* blendState, _In_opt_ ID3D11SamplerState* samplerState, _In_opt_ ID3D11DepthStencilState* depthStencilState, _In_opt_ ID3D11RasterizerState* rasterizerState, _In_opt_ std::function<void()> setEffect)
{
	if(bBegan)
	{
		MessageBox( NULL, L"You can't nest begin calls", L"Warning", MB_OK );
		throw std::exception("You can't nest begin calls");
	}

	bBegan = true;

	SortMode = sortMode;

	spriteList.clear();

	ID3D11Device* device = getGraphicsDevice()->getDevice();

	if(pVertexShader == nullptr)
	{
		// Compile the vertex shader
		ID3DBlob* pVSBlob = NULL;
		HRESULT hr = RCGame::CompileShaderFromFile( L"SpriteBatch.fx", "VS", "vs_4_0", &pVSBlob );
		if( FAILED( hr ) )
		{
			MessageBox( NULL,
						L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
			return;
		}

		// Create the vertex shader
		hr = device->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &pVertexShader );
		if( FAILED( hr ) )
		{    
			pVSBlob->Release();
			return;
		}		

		UINT numElements = ARRAYSIZE( layout );

		// Create the input layout
		hr = device->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
											  pVSBlob->GetBufferSize(), &pVertexLayout );
		pVSBlob->Release();

		ID3DBlob* pVSBlobInst = NULL;
		hr = RCGame::CompileShaderFromFile( L"SpriteBatch.fx", "VI", "vs_4_0", &pVSBlobInst );
		if( FAILED( hr ) )
		{
			MessageBox( NULL,
						L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
			return;
		}

		// Create the vertex shader
		hr = device->CreateVertexShader( pVSBlobInst->GetBufferPointer(), pVSBlobInst->GetBufferSize(), NULL, &pVertexShaderInstanced );
		if( FAILED( hr ) )
		{    
			pVSBlobInst->Release();
			return;
		}

		numElements = ARRAYSIZE( layout );

		// Create the input layout
		hr = device->CreateInputLayout( layout, numElements, pVSBlobInst->GetBufferPointer(),
											  pVSBlobInst->GetBufferSize(), &pVertexLayoutInstanced );
		pVSBlobInst->Release();

		// Compile the pixel shader
		ID3DBlob* pPSBlob = NULL;
		hr = RCGame::CompileShaderFromFile( L"SpriteBatch.fx", "PS", "ps_4_0", &pPSBlob );
		if( FAILED( hr ) )
		{
			MessageBox( NULL,
						L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
			return;
		}

		// Create the pixel shader
		hr = device->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &pPixelShader );
		pPSBlob->Release();
		if( FAILED( hr ) )
			return;

		// Create vertex buffer
		D3D11_BUFFER_DESC bd;
		ZeroMemory( &bd, sizeof(bd) );
		bd.Usage = D3D11_USAGE_DYNAMIC;
		bd.ByteWidth = sizeof( PositionTexVertex ) * 4;
		bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		D3D11_SUBRESOURCE_DATA InitData;
		ZeroMemory( &InitData, sizeof(InitData) );
		InitData.pSysMem = vertices;
		hr = device->CreateBuffer( &bd, &InitData, &pVertexBuffer );
		if( FAILED( hr ) )
			return;

		// Build index
		bd.Usage = D3D11_USAGE_DEFAULT;
		bd.ByteWidth = sizeof( WORD ) * 12;
		bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		bd.CPUAccessFlags = 0;
		InitData.pSysMem = indices;
		hr = device->CreateBuffer( &bd, &InitData, &pIndexBuffer );
		if( FAILED( hr ) )
			return;

		// Create the constant buffers
		bd.Usage = D3D11_USAGE_DEFAULT;
		bd.ByteWidth = sizeof(CBParameters);
		bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		bd.CPUAccessFlags = 0;
		hr = device->CreateBuffer( &bd, NULL, &pParameters );
		if( FAILED( hr ) )
			return;    		
	}

	if(!depthStencilState)
		CreateDepthStencilState(false,false,&depthStencilState);
	
	if(!blendState)
		getAlphaBlend(&blendState);

	if(!samplerState)
		CreateSamplerState(D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,D3D11_TEXTURE_ADDRESS_CLAMP,&samplerState);

	if(!rasterizerState)
		CreateRasterizerState(D3D11_CULL_BACK,D3D11_FILL_SOLID,&rasterizerState);

	customShader = setEffect;
	
	pGraphicsDevice->getDeviceContext()->OMGetBlendState(&pBlendState,nullptr,nullptr);
	pGraphicsDevice->getDeviceContext()->OMGetDepthStencilState(&pDepthStencilState,nullptr);
	pGraphicsDevice->getDeviceContext()->HSGetSamplers(0,1,&pSamplerState);
	pGraphicsDevice->getDeviceContext()->RSGetState(&pRasterizerState);

	pGraphicsDevice->getDeviceContext()->OMSetBlendState(blendState,nullptr,0xFFFFFFFF);
	pGraphicsDevice->getDeviceContext()->OMSetDepthStencilState(depthStencilState,0);
	pGraphicsDevice->getDeviceContext()->HSSetSamplers(0,1,&samplerState);
	pGraphicsDevice->getDeviceContext()->RSSetState(rasterizerState);
	pGraphicsDevice->getDeviceContext()->PSSetSamplers( 0, 1, &samplerState );
}

void RCSpriteBatch::Draw(ID3D11ShaderResourceView* texture, XMFLOAT4 source, XMFLOAT4 destination, XMFLOAT2 origin, float rotation, XMFLOAT4 color,  float depth)
{
	std::shared_ptr<RCSprite> sprite(new RCSprite());

	if(SortMode != Immediate)
	{
		Draw(texture,destination,origin,rotation,color,depth);

		// Get the last item in the list and set it's source.
		sprite = (std::shared_ptr<RCSprite>)(spriteList)[spriteList.size()-1];
	}
	else
	{
		sprite->texture = texture;
		sprite->position = XMFLOAT2(destination.x,destination.y);
		sprite->dimensions = XMFLOAT2(destination.z / 2,destination.w / 2);
		sprite->origin = origin;
		sprite->color = color;
		sprite->rotation = rotation;
		sprite->depth = depth;

		sprite->texMod = XMFLOAT4(0,0,1,1);
	}

	XMVECTOR imgsize = RCGame::GetTextureSize(sprite->texture);
	float iW = XMVectorGetX(imgsize);
	float iH = XMVectorGetY(imgsize);
	
	if(source.z != 0)
		sprite->texMod.z = source.z / iW; 

	if(source.w != 0)
		sprite->texMod.w = source.w / iH; 

	sprite->texMod.x = 1 / (iW / source.x);
	sprite->texMod.y = 1 / (iH / source.y);

	if(sprite->texMod.x >= 1)
		sprite->texMod.x = 0;

	if(sprite->texMod.y >= 1)
		sprite->texMod.y = 0;

	XMStoreFloat4(&sprite->texMod, XMVectorClamp(XMVectorSet(sprite->texMod.x,sprite->texMod.y,sprite->texMod.z,sprite->texMod.w),XMVectorSet(0,0,0,0),XMVectorSet(1,1,1,1)));

	if(SortMode == Immediate)
		RenderSprite(sprite);
}
void RCSpriteBatch::Draw(ID3D11ShaderResourceView* texture, XMFLOAT4 destination, XMFLOAT2 origin, float rotation, XMFLOAT4 color,  float depth)
{
	if(!texture)
	{
		MessageBox( NULL, L"You must supply a texture", L"Warning", MB_OK );
		throw std::exception("You must supply a texture");
	}

	if(!bBegan)
	{
		MessageBox( NULL, L"Begin must be called before Draw", L"Warning", MB_OK );
		throw std::exception("Begin must be called before Draw");
	}

	//RCSprite* sprite = new RCSprite();
	std::shared_ptr<RCSprite> sprite(new RCSprite());
	
	sprite->texture = texture;
	sprite->position = XMFLOAT2(destination.x,destination.y);
	sprite->dimensions = XMFLOAT2(destination.z / 2,destination.w / 2);
	sprite->origin = origin;
	sprite->color = color;
	sprite->rotation = rotation;
	sprite->depth = depth;

	sprite->texMod = XMFLOAT4(0,0,1,1);

	if(SortMode != Immediate)
	{
		spriteList.push_back(sprite);
	}
	else
	{
		RenderSprite(sprite);
	}
}

void RCSpriteBatch::End()
{
	if(!bBegan)
	{
		MessageBox( NULL, L"Begin must be called before End", L"Warning", MB_OK );
		throw std::exception("Begin must be called before End");
	}

	if(SortMode != Immediate)
	{
		// Sort them based on sort mode.
		switch(SortMode)
		{
			case Texture:
				std::sort(spriteList.begin(),spriteList.end(),[](std::shared_ptr<RCSprite> x, std::shared_ptr<RCSprite> y) -> bool
				{
					return x->texture < y->texture;
				});
				break;
			case BackToFront:
				std::sort(spriteList.begin(),spriteList.end(),[](std::shared_ptr<RCSprite> x, std::shared_ptr<RCSprite> y) -> bool
				{
					return x->depth > y->depth;
				});				
				break;
			case FrontToBack:
			case Deferred:
				std::sort(spriteList.begin(),spriteList.end(),[](std::shared_ptr<RCSprite> x, std::shared_ptr<RCSprite> y) -> bool
				{
					return x->depth < y->depth;
				});
				break;
		}
		
		if(SortMode != Instanced)
		{
			// TODO
			// Write them all out to a single vertex buffer and draw them in one go....
			
			// Draw all the sprites :)
			for(auto s = spriteList.begin();s != spriteList.end();s++)
			{
				std::shared_ptr<RCSprite> sprite = (*s);
				RenderSprite(sprite); 
			}
		}
		else
		{
			// Order by depth.
			std::sort(spriteList.begin(),spriteList.end(),[](std::shared_ptr<RCSprite> x, std::shared_ptr<RCSprite> y) -> bool
				{
					return x->depth < y->depth;
				});

			//std::vector<std::shared_ptr<RCSprite>> orderTextureList = spriteList;
			/*std::sort(orderTextureList.begin(),orderTextureList.end(),[](std::shared_ptr<RCSprite> x, std::shared_ptr<RCSprite> y) -> bool
					{
						return x->texture < y->texture;
					});*/

			
			std::vector<tIdx*> textures;
						
			for(auto s = spriteList.begin();s != spriteList.end();s++)
			{
				tIdx* texture = new tIdx();
				texture->texture = (*s)->texture;
				texture->Cnt = 1;
				texture->sprite = (*s);

				for(auto t = s+1;t != spriteList.end();t++)
				{
					ID3D11ShaderResourceView* txtr = (*t)->texture;
					if(txtr != texture->texture)
					{
						textures.push_back(texture);
						s = t-1;
						break;
					}
					else
					{
						texture->Cnt++;
						if(t == spriteList.end()-1)
						{	
							textures.push_back(texture);
							s = t-1;							
						}
					}
				}
			}
			
			// Build instance list for this texture..
			for(auto is = textures.begin();is != textures.end();is++)
			{
				int matCnt = (*is)->Cnt;
				XMMATRIX* instMats = new XMMATRIX[matCnt];
				int cnt = 0;
				for(auto s = spriteList.begin();s != spriteList.end();s++)
				{
					std::shared_ptr<RCSprite> sprite = (*s);
					if(sprite->texture == (*is)->texture)
					{
						instMats[cnt] = GetSpriteWorld(sprite);
						cnt++;
					}
				}
				
				ZeroMemory( &InstData, sizeof(InstData) );
				InstData.pSysMem = instMats;

				D3D11_BUFFER_DESC bufferDesc =
				{
					( matCnt ) * sizeof( XMMATRIX ),
					D3D11_USAGE_DYNAMIC,
					D3D11_BIND_VERTEX_BUFFER,
					D3D11_CPU_ACCESS_WRITE,
					0
				};

				getGraphicsDevice()->getDevice()->CreateBuffer( &bufferDesc, &InstData, &pInstanceuffer );

				RenderSprite((*is)->sprite); 				
			}

			textures.clear();		
		}
	}

	pGraphicsDevice->getDeviceContext()->OMSetBlendState(pBlendState,nullptr,0xFFFFFFFF);
	pGraphicsDevice->getDeviceContext()->OMSetDepthStencilState(pDepthStencilState,0);

	pGraphicsDevice->getDeviceContext()->HSSetSamplers(0,1,&pSamplerState);
	pGraphicsDevice->getDeviceContext()->RSSetState(pRasterizerState);

	pGraphicsDevice->getDeviceContext()->PSSetSamplers( 0, 1, &pSamplerState );

	bBegan = false;
}

void RCSpriteBatch::RenderSprite(std::shared_ptr<RCSprite> sprite)
{
	ID3D11DeviceContext* context = pGraphicsDevice->getDeviceContext();

	// Set the input layout
	context->IASetInputLayout( pVertexLayout );

	// Set vertex buffer
	UINT stride[2] = {sizeof( PositionTexVertex ), sizeof(XMMATRIX)};
	UINT offset[2] = {0,0};

	// Initialize matrix
	CBParameters cbParameters;
	
	cbParameters.vMeshColor = sprite->color;
	cbParameters.f4TexMods = sprite->texMod;
		

	if(SortMode == Instanced)
	{
		ID3D11Buffer* pBuffers[2] =
		{
			pVertexBuffer, pInstanceuffer
		};
		
		cbParameters.MatrixTransform = GetViewportTransform();
		
		context->IASetVertexBuffers( 0, 2, pBuffers, stride, offset );
		context->VSSetShader( pVertexShaderInstanced, NULL, 0 );

		
	}
	else
	{
		context->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride[0], &offset[0] );

		cbParameters.MatrixTransform =  GetSpriteWorld(sprite) * GetViewportTransform();

		context->VSSetShader( pVertexShader, NULL, 0 );		
	}

	context->VSSetConstantBuffers( 0, 1, &pParameters );

	context->UpdateSubresource( pParameters, 0, NULL, &cbParameters, 0, 0 );  
	
	// Set index buffer
	context->IASetIndexBuffer( pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
	
	// Set primitive topology
	context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );	  

	// Render the sprite	
	context->PSSetShader( pPixelShader, NULL, 0 );
	context->PSSetConstantBuffers( 0, 1, &pParameters );
	context->PSSetShaderResources( 0, 1, &(sprite->texture) );
	

	if(customShader)
		customShader();

	if(SortMode == Instanced)		
		context->DrawIndexedInstanced(6,spriteList.size(),0,0,0);
	else
		context->DrawIndexed( 6, 0, 0 );

	//delete &cbParameters;
}

XMMATRIX RCSpriteBatch::GetSpriteWorld(std::shared_ptr<RCSprite> sprite)
{
	XMVECTOR size = RCGame::GetTextureSize(sprite->texture);
	XMFLOAT2 imageSize = XMFLOAT2(XMVectorGetX(size),XMVectorGetY(size));
	XMFLOAT2 originCalc = sprite->origin;

	XMFLOAT2 center = XMFLOAT2(imageSize.x/2,imageSize.y/2);
	center = XMFLOAT2(sprite->dimensions.x,sprite->dimensions.y);
	XMFLOAT2 ratio(center.x/originCalc.x,center.y/originCalc.y);
	originCalc = XMFLOAT2(sprite->dimensions.x/(ratio.x),sprite->dimensions.y/ratio.y);

	//XMMATRIX rotOffsetMat = XMMatrixTranslation(sprite->dimensions.x - originCalc.x,sprite->dimensions.y - originCalc.y,0) * XMMatrixRotationZ(sprite->rotation) * XMMatrixTranslation(originCalc.x-sprite->dimensions.x,originCalc.y-sprite->dimensions.y,0);
	XMMATRIX rotOffsetMat = XMMatrixTranslation(sprite->dimensions.x - originCalc.x,sprite->dimensions.y - originCalc.y,0) * XMMatrixRotationZ(sprite->rotation);// * XMMatrixTranslation(sprite->dimensions.x,sprite->dimensions.y,0);
		
	return XMMatrixScaling(sprite->dimensions.x,sprite->dimensions.y,0) * rotOffsetMat * XMMatrixTranslation(sprite->position.x,sprite->position.y,0);
}

HRESULT RCSpriteBatch::CreateDepthStencilState(bool enable, bool writeEnable, _Out_ ID3D11DepthStencilState** pResult)
{
    D3D11_DEPTH_STENCIL_DESC desc;
    ZeroMemory(&desc, sizeof(desc));

    desc.DepthEnable = enable;
    desc.DepthWriteMask = writeEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
    desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;

    desc.StencilEnable = false;
    desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;

    desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
    desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;

    desc.BackFace = desc.FrontFace;

    return pGraphicsDevice->getDevice()->CreateDepthStencilState(&desc, pResult);
}
HRESULT RCSpriteBatch::CreateBlendState(D3D11_BLEND srcBlend, D3D11_BLEND destBlend, _Out_ ID3D11BlendState** pResult)
{
    D3D11_BLEND_DESC desc;
    ZeroMemory(&desc, sizeof(desc));

    desc.RenderTarget[0].BlendEnable = (srcBlend != D3D11_BLEND_ONE) ||
                                       (destBlend != D3D11_BLEND_ZERO);

    desc.RenderTarget[0].SrcBlend  = desc.RenderTarget[0].SrcBlendAlpha  = srcBlend;
    desc.RenderTarget[0].DestBlend = desc.RenderTarget[0].DestBlendAlpha = destBlend;
    desc.RenderTarget[0].BlendOp   = desc.RenderTarget[0].BlendOpAlpha   = D3D11_BLEND_OP_ADD;

    desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    return pGraphicsDevice->getDevice()->CreateBlendState(&desc, pResult);
}
HRESULT RCSpriteBatch::CreateSamplerState(D3D11_FILTER filter, D3D11_TEXTURE_ADDRESS_MODE addressMode, _Out_ ID3D11SamplerState** pResult)
{
    D3D11_SAMPLER_DESC desc;
    ZeroMemory(&desc, sizeof(desc));

    desc.Filter = filter;

    desc.AddressU = addressMode;
    desc.AddressV = addressMode;
    desc.AddressW = addressMode;

    desc.MaxLOD = FLT_MAX;
    desc.MaxAnisotropy = 16;
    desc.ComparisonFunc = D3D11_COMPARISON_NEVER;

	return pGraphicsDevice->getDevice()->CreateSamplerState(&desc, pResult);
}
HRESULT RCSpriteBatch::CreateRasterizerState(D3D11_CULL_MODE cullMode, D3D11_FILL_MODE fillMode, _Out_ ID3D11RasterizerState** pResult)
{
    D3D11_RASTERIZER_DESC desc;
    ZeroMemory(&desc, sizeof(desc));

    desc.CullMode = cullMode;
    desc.FillMode = fillMode;
    desc.DepthClipEnable = true;
    desc.MultisampleEnable = true;

    return pGraphicsDevice->getDevice()->CreateRasterizerState(&desc, pResult);
}

HRESULT RCSpriteBatch::getOpaque(_Out_ ID3D11BlendState** pResult)
{
	return CreateBlendState(D3D11_BLEND_ONE, D3D11_BLEND_ZERO, pResult);
}

HRESULT RCSpriteBatch::getAlphaBlend(_Out_ ID3D11BlendState** pResult)
{
	return CreateBlendState(D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, pResult);
}

HRESULT RCSpriteBatch::getAdditive(_Out_ ID3D11BlendState** pResult)
{
	return CreateBlendState(D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_ONE, pResult);
}

HRESULT RCSpriteBatch::getNonPremultiplied(_Out_ ID3D11BlendState** pResult)
{
	return CreateBlendState(D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, pResult);
}